package com.hung.nio;
/**
 * title:NIODemoServer.java
 * author: hungki
 * createTime 18/8/30 下午 3:38
 * version v_1.0
 * Copyright @ 2018 复华创新事业部
 */

import com.sun.org.apache.bcel.internal.generic.Select;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Calendar;
import java.util.Iterator;

/**
 * className: NIODemoServer 
 * describe: 
 * author: hungki  
 * createTime 18/8/30 下午 3:38 
 *
 */
public class NIODemoServer implements Runnable {
    private Selector selector ;
    private ByteBuffer readBuffer = ByteBuffer.allocate(1024);
    private ByteBuffer writeBuffer = ByteBuffer.allocate(1024);

    NIODemoServer(int port){
        try {
            //打开多路复用器
            this.selector = Selector.open();
            //打开服务端管道
            ServerSocketChannel ssc = ServerSocketChannel.open();
            //配置为非阻塞模式
            ssc.configureBlocking(false);
            //绑定地址
            ssc.bind(new InetSocketAddress(port));
            //注册服务端管道到多路复用器上,并监听OP_ACCEPT状态的key
            ssc.register(this.selector, SelectionKey.OP_ACCEPT);
            System.out.println("Server started , port = " + port);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        while(true){
            try {
                this.selector.select();
                Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator();
                while(keys.hasNext()){
                    //获取一个已经准备好的key，这个key对应一个ServerSocketChannel
                    SelectionKey sk = keys.next();
                    keys.remove();

                    if(sk.isValid()){
                        if(sk.isAcceptable()){
                            //System.out.println("sk.isAcceptable() = " + sk.isAcceptable());
                            this.accept(sk);
                        }
                        if(sk.isReadable()){
                            this.read(sk);
                        }
                        if(sk.isWritable()){
                            this.write(sk);
                        }

                    }

                }

            } catch (IOException e) {

            }

        }
    }

    private void write(SelectionKey sk) throws IOException {
        this.writeBuffer.clear();
        SocketChannel sc = (SocketChannel)sk.channel();
        sc.configureBlocking(false);
        String response = "Server Write : hello" + Calendar.getInstance().toString();
        writeBuffer.put(response.getBytes());
        writeBuffer.flip();
        sc.write(writeBuffer);

        //sk.channel().close();
        //sk.cancel();
        return;

    }

    private void read(SelectionKey sk) throws IOException {
        this.readBuffer.clear();
        SocketChannel sc = (SocketChannel)sk.channel();
        int count = sc.read(this.readBuffer);
        if(count==-1){
            sk.channel().close();
            sk.cancel();
            return;
        }
        this.readBuffer.flip();
        byte[] bytes = new byte[this.readBuffer.remaining()];
        this.readBuffer.get(bytes);

        String body = new String(bytes).trim();
        System.out.println("Server : "  + body);
        //sk.channel().close();
        //sk.cancel();
        return;
    }

    private void accept(SelectionKey sk) throws IOException {
        ServerSocketChannel ssc =(ServerSocketChannel)sk.channel();
        SocketChannel sc = ssc.accept();
        //System.out.println("ssc = " + ssc);
        //System.out.println("ssc.accept() = " + sc);
        if(null!=sc) {
            sc.configureBlocking(false);
            sc.register(this.selector, SelectionKey.OP_READ);
        }
    }

    public static void main(String[] args) {
        NIODemoServer server = new NIODemoServer(8765);
        new Thread(server).start();
    }
}
